package cn.hejiang.mamis.core.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.ssssssss.magicapi.core.service.MagicResourceService;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.hejiang.mamis.core.entity.PlatSys;
import cn.hejiang.mamis.core.entity.PlatUser;
import cn.hejiang.mamis.core.entity.SysMenu;
import cn.hejiang.mamis.core.entity.SysRole;
import cn.hejiang.mamis.core.magic.MagicResourceServiceImpl;
import cn.hejiang.mamis.core.mapper.PlatSysMapper;
import cn.hejiang.mamis.core.service.PlatSysService;
import cn.hejiang.mamis.core.service.SysMenuService;
import cn.hejiang.mamis.core.service.SysRoleService;
import cn.hutool.extra.spring.SpringUtil;

@Service
@CacheConfig(keyGenerator = "cacheKeyGenerator")
public class PlatSysServiceImpl extends ServiceImpl<PlatSysMapper, PlatSys> implements PlatSysService {
	@Autowired
	SysRoleService sysRoleService;

	@Autowired
	SysMenuService sysMenuService;

	@Cacheable(cacheNames = "PLAT_SYS")
	public List<PlatSys> getSysList() {
		return this.getBaseMapper().getSysList();
	}

	@Cacheable(cacheNames = "PLAT_SYS")
	public List<PlatSys> getSysListByStatus(int status) {
		return this.getBaseMapper().getSysListByStatus(status);
	}

	@Cacheable(cacheNames = "PLAT_SYS")
	public PlatSys getSysByCode(String code) {
		return this.getBaseMapper().getSysByCode(code);
	}

	@Cacheable(cacheNames = "PLAT_SYS")
	public PlatSys getSysById(String id) {
		return this.getBaseMapper().getSysById(id);
	}

	@Cacheable(cacheNames = "PLAT_SYS")
	public PlatSys getSysByCName(String cname) {
		return this.getBaseMapper().getSysByCName(cname);
	}

	@CacheEvict(cacheNames = "PLAT_SYS", allEntries = true)
	public boolean save(PlatSys sys) {
		return super.save(sys);
	}

	@CacheEvict(cacheNames = "PLAT_SYS", allEntries = true)
	public boolean update(PlatSys sys, Wrapper<PlatSys> wrapper) {
		return super.update(sys, wrapper);
	}

	@Transactional
	@CacheEvict(cacheNames = { "PLAT_SYS", "SYS_MENU", "SYS_ROLE", "SYS_ROLE_MENU", "SYS_USER_MENU" }, allEntries = true)
	public boolean createSys(PlatSys sys, String sysId, String curUserId) {
		// 新建系统
		int ret = addSys(sys, sysId, curUserId);
		if (ret == 0) {
			throw new RuntimeException("写入数据库失败");
		}

		// 新建角色
		SysRole roleAdmin = addSysRole("admin", "管理人员", sys.getId(), curUserId);
		SysRole roleUser = addSysRole("user", "使用人员", sys.getId(), curUserId);

		// 新建菜单（并关联到角色）
		addSysMenuList(sys.getId(), curUserId, roleAdmin, roleUser);

		// 初始化 magic-api 目录
		MagicResourceService magicResourceService = SpringUtil.getBean(MagicResourceService.class);
		((MagicResourceServiceImpl) magicResourceService).initSys(sys.getId());

		return ret > 0;
	}

	private int addSys(PlatSys sys, String sysId, String curUserId) {
		sys.setId(null);
		sys.setCreatedBy(curUserId);
		sys.setOwnSysId(sysId);

		return this.getBaseMapper().insert(sys);
	}

	private List<SysMenu> addSysMenuList(String sysId, String userId, SysRole roleAdmin, SysRole roleUser) {
		List<SysMenu> list = new ArrayList<>();

		SysMenu mgmt = addMenuItem(null, "系统管理", "fa fa-cog", "/sys", SysMenu.TYPE_GROUP, null, 11, sysId, userId);
		SysMenu menu = addMenuItem(mgmt.getId(), "菜单管理", "fa fa-list", "/sys/menu", SysMenu.TYPE_STATIC_PAGE,
				"sys-menu", 11, sysId, userId);
		SysMenu role = addMenuItem(mgmt.getId(), "权限管理", "fa fa-list", "/sys/role", SysMenu.TYPE_STATIC_PAGE,
				"sys-role", 21, sysId, userId);

		SysMenu dev = addMenuItem(null, "开发管理", "fa fa-cog", "/dev", SysMenu.TYPE_GROUP, null, 21, sysId, userId);
		SysMenu page = addMenuItem(dev.getId(), "页面开发", "fa fa-list", "/dev/page", SysMenu.TYPE_STATIC_PAGE, "dev-page",
				11, sysId, userId);
		SysMenu intf = addMenuItem(dev.getId(), "接口开发", "fa fa-list", "/dev/api", SysMenu.TYPE_STATIC_PAGE, "dev-api",
				21, sysId, userId);

		list.add(mgmt);
		list.add(menu);
		list.add(role);
		list.add(dev);
		list.add(page);
		list.add(intf);

		// 关联菜单与角色
		sysRoleService.addRoleMenu(roleAdmin.getId(), mgmt.getId(), sysId, userId);
		sysRoleService.addRoleMenu(roleAdmin.getId(), menu.getId(), sysId, userId);
		sysRoleService.addRoleMenu(roleAdmin.getId(), role.getId(), sysId, userId);

		sysRoleService.addRoleMenu(roleAdmin.getId(), dev.getId(), sysId, userId);
		sysRoleService.addRoleMenu(roleAdmin.getId(), page.getId(), sysId, userId);
		sysRoleService.addRoleMenu(roleAdmin.getId(), intf.getId(), sysId, userId);

		return list;
	}

	private SysMenu addMenuItem(String pid, String name, String icon, String url, int type, String pageId, int seq,
			String sysId, String userId) {
		SysMenu menu = new SysMenu();

		menu.setPid(pid);
		menu.setName(name);
		menu.setIcon(icon);
		menu.setUrl(url);
		menu.setType(type);
		menu.setPageId(pageId);
		menu.setSeq(seq);
		menu.setOwnSysId(sysId);
		menu.setCreatedBy(userId);
		menu.setUpdatedBy(userId);

		boolean ret = sysMenuService.save(menu);
		if (!ret) {
			throw new RuntimeException("写入数据库失败");
		}

		return menu;
	}

	private SysRole addSysRole(String roleName, String roleDescr, String sysId, String curUserId) {
		SysRole role = new SysRole();

		role.setName(roleName);
		role.setDescr(roleDescr);
		role.setOwnSysId(sysId);
		role.setCreatedBy(curUserId);
		role.setUpdatedBy(curUserId);

		boolean ret = sysRoleService.save(role);
		if (!ret) {
			throw new RuntimeException("写入数据库失败");
		}

		return role;
	}

	@Transactional
	@CacheEvict(cacheNames = { "SYS_ROLE_USER", "SYS_USER_MENU" }, allEntries = true)
	public int setSysAdmins(String sysId, String[] userIds, String curUserId) {
		// 获取系统管理员角色
		SysRole adminRole = sysRoleService.getRoleByName("admin", sysId, null);

		// 清理已有用户
		sysRoleService.clearRoleUser(adminRole.getId(), sysId);

		// 关联新用户
		int ret = Arrays.asList(userIds).stream().map(userId -> {
			return sysRoleService.addRoleUser(adminRole.getId(), userId, sysId, curUserId);
		}).collect(Collectors.summingInt(i -> i));

		return ret;
	}

	@Cacheable(cacheNames = "SYS_ROLE_USER")
	public List<PlatUser> getSysAdminList(String sysId) {
		// 获取系统管理员角色
		SysRole adminRole = sysRoleService.getRoleByName("admin", sysId, null);
		return sysRoleService.getRoleUserList(adminRole.getId(), sysId);
	}
}
